#pragma once

#include "Sock.hpp"
#include <poll.h>
#include <assert.h>

#define FD_NONE -1
#define NFDS 100

class PollServer {
public:
  PollServer(uint16_t port = 8080) 
    :_port(port)
    ,_nfds(NFDS)
  {
    _listenSock = Socket::SockInit();

    Socket::SockBind(_listenSock, _port);

    Socket::SockListen(_listenSock);

    _fds = new pollfd[_nfds];
    for(int i = 0; i < _nfds; i++) {
      _fds[i].fd = FD_NONE;
      _fds[i].events = _fds[i].revents = 0;
    }

    _fds[0].fd = _listenSock;
    _fds[0].events = POLLIN;
  }

  void showFds() {
    std::cout << "fds:: ";
    for(int i = 0; i < _nfds; i++) {
      if(_fds[i].fd == FD_NONE) {
        continue;
      }
      std::cout << _fds[i].fd << " ";
    }
    std::cout << std::endl;
  }

  void Start() {
    while(1) {
      showFds();

      int res = poll(_fds, _nfds, -1);
      if(res > 0) {
        std::cout << "some fds`s ready" << std::endl;
        EventHandler();
      } else if(res == 0) {
        std::cout << "time out" << std::endl;
      } else {
        printf("poll err, errno[%d], strerror:%s", errno, strerror(errno));
      }
    }
  }

  void EventHandler() {
    for(int i = 0; i < _nfds; i++) {
      if(_fds[i].fd == FD_NONE) {
        continue;
      }

      if(_fds[i].revents & POLLIN) {
        if(i == 0) {
          Accept();
        } else {
          Reader(i);
        }
      }
    }
  }

  void Accept() {
    std::string clientIP;
    uint16_t clientPort;
    int sock = Socket::SockAccept(_listenSock, clientIP, clientPort);
    
    int pos = 1;
    for(; pos < _nfds; pos++) {
      if(_fds[pos].fd == FD_NONE) {
        break;
      }
    }

    if(pos == _nfds) {
      std::cout << "fds is full" << std::endl;
      close(sock);
    } else {
      std::cout << "get a new link ::" << sock << std::endl;
      _fds[pos].fd = sock;
      _fds[pos].events = POLLIN;
    }
  }

  void Reader(int pos) {
    char buff[1024];
    int res = read(_fds[pos].fd, buff, sizeof(buff) - 1);
    if(res > 0) {
      buff[res] = 0;
      std::cout << "client #" << buff << std::endl;
    } else if(res == 0) {
      std::cout << "client " << _fds[pos].fd << "is closed" << std::endl;

      close(_fds[pos].fd);
      _fds[pos].fd = FD_NONE;
      _fds[pos].events = _fds[pos].revents = 0;
    } else {
      printf("read err, errno[%d], strerror::%s", errno, strerror(errno));
      close(_fds[pos].fd);
      _fds[pos].fd = FD_NONE;
      _fds[pos].events = _fds[pos].revents = 0;
    }
  }

  ~PollServer() {
    if(_listenSock >= 0) {
      close(_listenSock);
    }

    if(_fds != nullptr) {
      delete []_fds;
    }
  }
private:
  uint16_t _port;
  int _listenSock;
  int _nfds;
  pollfd* _fds;
};
